# -*- coding: utf-8 -*-
import re
import jieba
import jieba.posseg as pseg
from .infrastructure import SuperMap
import requests as req


# 代表一个(省，市，区)组成的地点
class Location:

    # 直辖市
    # municipality = ["北京市", "天津市", "上海市", "重庆市"]

    def __init__(self, addressAll):
        self.apiHttp = "https://restapi.amap.com/v5/place/text"  # 高德api接口
        self.apikey = "40d7b64135b94d60d6e91730a70e47de"  # key
        self.apiHttpBaidu = "https://api.map.baidu.com/place/v2/search"  # 百度api接口
        self.apikeyBaidu = "yuMeXqyGVd62yDPF74pFO7yo8zTXywVq"  # key
        self.addressAll = addressAll  # 原始地址
        self.province = Province()
        self.city = City()
        self.area = Area()
        self.address = Address()
        self.tsrl = Tsrl()  # 街路巷地址
        self.qx = {
            '市辖县': '市辖区',
            '玄武县': '玄武区',
            '鼓楼县': '鼓楼区',
            '秦淮县': '秦淮区',
            '建邺县': '建邺区',
            '浦口县': '浦口区',
            '栖霞县': '栖霞区',
            '雨花台县': '雨花台区',
            '江宁县': '江宁区',
            '六合县': '六合区',
            '溧水县': '溧水区',
            '高新开发县': '高新开发区',
            '经济技术开发县': '经济技术开发区'
        }

    def setPlace(self, name, place_type):
        if not hasattr(self, place_type):
            from .exceptions import PlaceTypeNotExistException
            raise PlaceTypeNotExistException(place_type + \
                                             " 地区类型不存在")
        if getattr(self, place_type).isEmpty():
            getattr(self, place_type).setPlace(name)

    def pca_map(self, umap):
        self.dy = ""  # 单元号
        self.mp = ""  # 门牌号
        self.mphz = ""  # 门牌号后缀
        self.dl = ""  # 幢楼号
        self.dlhz = ""  # 幢楼后缀
        self.sh = ""  # 户室号
        self.shhz = ""  # 户室后缀
        if self.area.isEmpty():
            self.__city_and_province()
        else:
            if (self.area.name not in SuperMap.rep_areas) or (umap.get(self.area.name)):
                if umap.get(self.area.name):
                    tmp = umap.get(self.area.name)
                else:
                    tmp = SuperMap.area_city_mapper.get(self.area.name)
                if self.city.isEmpty() or self.city.precision == 0:
                    self.city.setPlace(tmp)
                elif self.city.isNotEmpty() and self.city.precision == 1:
                    if not self.area.isBlong(self.city.name) \
                            and umap.get(self.area.name) != self.city.name:
                        self.area.reset()
                self.__city_and_province()
            else:  # 重复区名 代码执行路径
                SuperMap.rep_area_set.add(self.area.name)
                if self.city.isNotEmpty():
                    self.__city_and_province()

        if self.city.name.isdigit():
            self.city.reset()

        # 对地址进行正则匹配
        # 门牌后缀/副号后缀（MPHZ/FHHZ）
        # 地址类型为0，说明是 门牌地址。地址描述到门牌号为止。结构组成为：省+市+行政区划+街路巷+门牌号
        #
        # 地址类型为1，说明是 幢楼地址。地址描述到幢楼号为止。结构组成为：省+市+行政区划+街路巷+门牌号+幢楼号
        #
        # 地址类型为2，说明是 户室地址。地址描述到单元号为止。结构组成为：省+市+行政区划+街路巷+门牌号+幢楼号+单元号+户室号。
        #
        # 地址类型为3，说明是 楼层地址。不在本此范围内。
        #
        # 地址类型为4，说明是 单元地址。地址描述到单元号为止。结构组成为：省+市+行政区划+街路巷+门牌号+幢楼号+单元号。

        address = "0" + self.address.name

        matchObj = re.match(r"([\s\S]+?)?([零一二三四五六七八九十〇壹贰叁肆伍陆柒捌玖貮两拾百佰千仟0-9]+)([区幢队组－-]|[号][－之西楼西上下]?)", address)

        if not matchObj:
            matchObj = re.match(r"([\s\S]+?)?([零一二三四五六七八九十〇壹贰叁肆伍陆柒捌玖貮两拾百佰千仟0-9]+)([号][－之西楼西上下]?)", address)
        if matchObj:
            if matchObj.group(1) is not None:
                address = "0" + address.replace(matchObj.group(1) + matchObj.group(2) + matchObj.group(3), "")
            else:
                address = "0" + address.replace(matchObj.group(2) + matchObj.group(3), "")

            # type 4
            if matchObj.group(3) == "幢" or matchObj.group(3) == "号楼" or matchObj.group(3) == "队":

                matchObj2 = re.match(
                    r"([\s\S]+?)?([零一二三四五六七八九十〇壹贰叁肆伍陆柒捌玖貮两拾百佰千仟0-9]+)?([幢栋排舍楼弄门队]?|[号楼]{2}?)([零一二三四五六七八九十〇壹贰叁肆伍陆柒捌玖貮两拾百佰千仟0-9]+)([单元]{2})",
                    address)
                if matchObj2:
                    # 单元号匹配成功

                    if matchObj2.group(3) is not None and matchObj2.group(2) is not None:
                        self.dl = matchObj2.group(2)
                        self.dlhz = matchObj2.group(3)
                        address = address.replace(matchObj2.group(2) + matchObj2.group(3), "")

                    self.dy = matchObj2.group(4)
                    self.mp = matchObj.group(2)
                    self.mphz = matchObj.group(3)
                    if matchObj2.group(1) is not None:

                        address = "0" + address.replace(matchObj2.group(1) + matchObj2.group(4) + matchObj2.group(5),
                                                        "")
                    else:

                        address = "0" + address.replace(matchObj2.group(4) + matchObj2.group(5), "")



                else:

                    matchObj2 = re.match(r"([\s\S]+?)?([零一二三四五六七八九十〇壹贰叁肆伍陆柒捌玖貮两拾百佰千仟0-9号]+)(["
                                         r"零一二三四五六七八九十〇壹贰叁肆伍陆柒捌玖貮两拾百佰千仟0-9]+)([单元]{2})",
                                         address)
                    if matchObj2:

                        self.dy = matchObj2.group(3)
                        # 门牌号
                        self.mp = matchObj.group(2)
                        self.mphz = matchObj.group(3)
                        if matchObj2.group(1) is not None:
                            address = "0" + address.replace(
                                matchObj2.group(1) + matchObj2.group(2) + matchObj2.group(3) + matchObj2.group(4), "")
                        else:
                            address = "0" + address.replace(
                                matchObj2.group(2) + matchObj2.group(3) + matchObj2.group(4), "")
                    else:
                        # 匹配户室号
                        matchObj2 = re.match(r'([\s\S]+?)?([零一二三四五六七八九十〇壹贰叁肆伍陆柒捌玖貮两拾百佰千仟0-9]+)([层室号])', address)
                        if matchObj2:
                            self.sh = matchObj2.group(2)
                            self.shhz = matchObj2.group(3)
                            # 栋楼号
                            self.dl = matchObj.group(2)
                            self.dlhz = matchObj.group(3)
                            if matchObj2.group(1) is not None:
                                address = "0" + address.replace(
                                    matchObj2.group(1) + matchObj2.group(2) + matchObj2.group(3), "")
                            else:
                                address = "0" + address.replace(matchObj2.group(2) + matchObj2.group(3), "")
                        else:

                            self.mp = matchObj.group(2)
                            self.mphz = matchObj.group(3)
                        pass

            else:
                # 不是幢 处理正常地址

                self.mp = matchObj.group(2)
                self.mphz = matchObj.group(3).replace("-", "－")


        else:

            pass

        if address != "":
            # 匹配栋楼号

            matchObj2 = re.match(r"([\s\S]+?)?([零一二三四五六七八九十〇壹贰叁肆伍陆柒捌玖貮两拾百佰千仟0-9]+)([\s\S]+?)?([幢栋排舍楼弄门队]|[号楼]{2})",
                                 address)
            if matchObj2:
                if matchObj2:
                    self.dl = matchObj2.group(2)
                    self.dlhz = matchObj2.group(4)
                    if matchObj2.group(3) is not None:
                        address = address.replace(matchObj2.group(3), "")
                    if matchObj2.group(1) is not None:
                        address = "0" + address.replace(matchObj2.group(1) + matchObj2.group(2) + matchObj2.group(4),
                                                        "")
                    else:
                        address = "0" + address.replace(matchObj2.group(2) + matchObj2.group(4), "")
            # 匹配单元号

            matchObj2 = re.match(r"([\s\S]+?)?([零一二三四五六七八九十〇壹贰叁肆伍陆柒捌玖貮两拾百佰千仟0-9]+)([\s\S]+?)?([单元]{2})", address)
            if matchObj2:
                self.dy = matchObj2.group(2)
                if matchObj2.group(3) is not None:
                    address = address.replace(matchObj2.group(3), "")
                if matchObj2.group(1) is not None:
                    address = "0" + address.replace(matchObj2.group(1) + matchObj2.group(2) + matchObj2.group(4), "")
                else:
                    address = "0" + address.replace(matchObj2.group(2) + matchObj2.group(4), "")
            # 匹配室号
            matchObj2 = re.match(r'([\s\S]+?)?([零一二三四五六七八九十〇壹贰叁肆伍陆柒捌玖貮两拾百佰千仟0-9]+)([\s\S]+?)?([层室号])', address)

            if matchObj2 and self.mphz != "－":
                self.sh = matchObj2.group(2)
                self.shhz = matchObj2.group(4)
                if matchObj2.group(3) is not None:
                    address = address.replace(matchObj2.group(3), "")
                if matchObj2.group(1) is not None:
                    address = address.replace(matchObj2.group(1) + matchObj2.group(2) + matchObj2.group(4), "")
                else:
                    address = address.replace(matchObj2.group(2) + matchObj2.group(4), "")

        import pandas as pd
        # 组装成DataFrame
        pd.set_option('display.width', 1000)
        pd.set_option('display.max_rows', None)

        pd.set_option('display.max_columns', None)
        # 处理单元号中的中文将其替换成数字
        if self.dy != "":
            self.dy = self.__chinese_to_arabic(self.dy)
            if int(self.dy) < 10:
                self.dy = "0" + self.dy

        if self.province.name == "" or self.city.name == "" or self.area.name == "" or self.tsrl.name == "":
            if self.city.name != "":
                # 对于有城市信息的优先使用百度api提高精准度

                res = req.get(
                    self.apiHttpBaidu + "?ak=" + self.apikeyBaidu + "&query=" + self.addressAll + "&region=" + self.city.name + "&output=json")
                resJson = res.json()

                if resJson['status'] == 0:
                    type = ""
                    if len(resJson["results"]) > 0:
                        # 取出第一个查询到的最相近地址
                        addressApiData = resJson["results"]
                        # 匹配最符合输入地址的项目
                        i = 0
                        for item, type in pseg.cut(self.addressAll):
                            if type == "xc":

                                self.tsrl.name = item
                                break
                        if type != "xc":
                            for data in addressApiData:
                                i += 1
                                for item, type in pseg.cut(data["name"]):
                                    print(item, type)
                                    if type == "xc":
                                        self.tsrl.name = item
                                        addressApiData = data
                                        break
                                if type == "xc":
                                    break
                        else:
                            addressApiData = resJson["results"][0]
                        # 街路巷

                        if type != "xc":
                            addressApiData = resJson["results"][0]
                            self.tsrl.name = addressApiData["name"]

                        # 省
                        if "province" in addressApiData:
                            self.province.name = addressApiData["province"].replace("省", "")

                        # 市
                        if "city" in addressApiData:
                            self.city.name = addressApiData["city"]
                        # 区
                        if "area" in addressApiData:
                            self.area.name = addressApiData["area"]
                else:

                    # 百度出现并发问题时访问高德
                    type = ""
                    res = req.get(self.apiHttp + "?key=" + self.apikey + "&keywords=" + self.addressAll)

                    resJson = res.json()
                    print("高德:"+self.addressAll)
                    print(resJson)
                    # 判断高德是否查询到相近地址
                    if len(resJson["pois"]) > 0:
                        # 取出第一个查询到的最相近地址
                        addressApiData = resJson["pois"]

                        # 匹配最符合输入地址的项目
                        i = 0
                        for item, type in pseg.cut(self.addressAll):

                            if type == "xc":
                                self.tsrl.name = item
                                break
                        if type != "xc":
                            for data in addressApiData:
                                i += 1

                                for item, type in pseg.cut(data["address"]):
                                    if type == "xc":
                                        self.tsrl.name = item
                                        addressApiData = data
                                        break
                                if type == "xc":
                                    break

                        else:
                            addressApiData = resJson["pois"][0]
                        # 街路巷

                        if type != "xc":
                            addressApiData = resJson["pois"][0]
                            self.tsrl.name = addressApiData["address"]

                        # 省
                        if "pname" in addressApiData:
                            self.province.name = addressApiData["pname"].replace("省", "")
                            # 市
                        if "cityname" in addressApiData:
                            self.city.name = addressApiData["cityname"]
                            # 区
                        if "adname" in addressApiData:
                            self.area.name = addressApiData["adname"]
            else:

                # 对没有匹配到的地址使用高德api进行二次解析
                type = ""
                res = req.get(self.apiHttp + "?key=" + self.apikey + "&keywords=" + self.addressAll)

                resJson = res.json()
                # 判断高德是否查询到相近地址
                if len(resJson["pois"]) > 0:
                    # 取出第一个查询到的最相近地址
                    addressApiData = resJson["pois"]

                    # 匹配最符合输入地址的项目
                    i = 0
                    for item, type in pseg.cut(self.addressAll):

                        if type == "xc":
                            self.tsrl.name = item
                            break
                    if type != "xc":
                        for data in addressApiData:
                            i += 1

                            for item, type in pseg.cut(data["address"]):
                                if type == "xc":
                                    self.tsrl.name = item
                                    addressApiData = data
                                    print(data)
                                    break
                            if type == "xc":
                                break

                    else:
                        addressApiData = resJson["pois"][0]
                    # 街路巷

                    if type != "xc":
                        addressApiData = resJson["pois"][0]
                        self.tsrl.name = addressApiData["name"]

                    # 街路巷

                    if type != "xc":
                        addressApiData = resJson["pois"][0]
                        self.tsrl.name = addressApiData["address"]

                    # 省
                    if "pname" in addressApiData:
                        self.province.name = addressApiData["pname"].replace("省", "")
                        # 市
                    if "cityname" in addressApiData:
                        self.city.name = addressApiData["cityname"]
                        # 区
                    if "adname" in addressApiData:
                        self.area.name = addressApiData["adname"]
        # 对于出现的中文进行数字转换
        if self.mp != "":
            self.mp = self.__chinese_to_arabic(self.mp)

        if self.dl != "":
            self.dl = self.__chinese_to_arabic(self.dl)

        if self.sh != "":
            self.sh = self.__chinese_to_arabic(self.sh)
        # 区县转换
        if self.qx.get(self.area.name):
            self.area.name = self.qx.get(self.area.name)
        return pd.DataFrame(
            {"地址名称": [self.addressAll], "行政区划中文": [self.province.name + self.city.name + self.area.name],
             "街路巷中文": [self.tsrl.name], "门牌号": [self.mp], "门牌后缀中文": [self.mphz], "幢楼号": [self.dl],
             "幢楼后缀中文": [self.dlhz], "单元号": [self.dy], "室号": [self.sh], "室号后缀中文": [self.shhz]})

    def __find_mh(self, data, text, index):
        """
        文本匹配最佳
        :param data: 数据
        :param text: 文本
        :param index: 索引
        :return:
        """
        arr_data = []
        for item_2 in text:
            for item in data:
                json_data = {
                    "text": "",
                    "number": 0
                }
                ret = item[index].find(item_2)
                if ret != -1:
                    json_data["text"] = item[index]
                    json_data["number"] += 1
                    arr_data.append(json_data)

        self.bubble_sort_pro(arr_data)
        return arr_data[len(arr_data) - 1]

    def bubble_sort_pro(self, our_list):
        """
        数组排序
        :param our_list:
        :return:
        """
        lastExchangeIndex = 0
        sortBorder = len(our_list) - 1  # 无序数组长度
        for _ in range(len(our_list) - 1):
            flag = True  # 循环标记
            for j in range(0, sortBorder):
                if our_list[j]["number"] > our_list[j + 1]["number"]:
                    our_list[j], our_list[j + 1] = our_list[j + 1], our_list[j]
                    flag = False  # 有元素交换，所以不跳出循环
                    lastExchangeIndex = j
            sortBorder = lastExchangeIndex
            if flag:
                break
        return our_list

    def __city_and_province(self):
        if self.city.isNotEmpty() and self.province.isNotEmpty():
            if not self.city.isBlong(self.province.name):
                if self.city.precision >= self.province.precision:
                    self.province.name = self.city.belong
                else:
                    self.city.reset()
        elif self.city.isNotEmpty() and self.province.isEmpty():
            self.province.name = self.city.belong


    def __chinese_to_arabic(self, cn: str) -> str:
        """
        中文转阿拉伯数字
        :param cn:
        :return:
        """
        # 文本是否包含int
        if_int = False
        CN_NUM = {
            '〇': 0, '一': 1, '二': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9, '零': 0,
            '壹': 1, '贰': 2, '叁': 3, '肆': 4, '伍': 5, '陆': 6, '柒': 7, '捌': 8, '玖': 9, '貮': 2, '两': 2,
        }
        CN_UNIT = {
            '十': 10,
            '拾': 10,
            '百': 100,
            '佰': 100,
            '千': 1000,
            '仟': 1000,
            '万': 10000,
            '萬': 10000,
            '亿': 100000000,
            '億': 100000000,
            '兆': 1000000000000,
        }
        if self.is_number(cn):
            return cn
        unit = 0  # current
        ldig = []  # digest
        for cndig in reversed(cn):
            if self.is_number(cndig):
                ldig.append(int(cndig))
                if_int = True
            elif cndig in CN_UNIT:
                unit = CN_UNIT.get(cndig)
                if unit == 10000 or unit == 100000000:
                    ldig.append(unit)
                    unit = 1
            else:
                dig = CN_NUM.get(cndig)
                if unit:
                    dig *= unit
                    unit = 0
                ldig.append(dig)

        if unit == 10:
            ldig.append(10)

        val, tmp = 0, 0
        if if_int is False:
            for x in reversed(ldig):
                if x == 10000 or x == 100000000:
                    val += tmp * x
                    tmp = 0
                else:
                    tmp += x
            val += tmp
        else:
            val, tmp = "", ""
            for x in reversed(ldig):
                tmp = str(x)
                val = val + tmp

        return str(val)

    def is_number(self, s):
        """
        判断文本是中文还是数字
        中文返回假，数字返回真
        :param s: str
        :return: bool
        """
        try:
            float(s)
            return True
        except ValueError:
            pass

        return False


class Place(object):

    def __init__(self, name=""):
        self.name = name
        self.precision = 1

    def reset(self):
        self.name = ""

    def isBlong(self, mayBe):
        return self.belong == mayBe

    def isEmpty(self):
        return False if self.name else True

    def isNotEmpty(self):
        return True if self.name else False


class City(Place):

    def __init__(self, name=""):
        super(City, self).__init__()

    def __getBlong(self):

        return SuperMap.city_province_mapper.get(self.name)

    def setPlace(self, name):
        self.name, isfilled = SuperMap.fillCity(name)
        if isfilled:  # 如果是需要补充字的，则认为这个匹配准确率比较低
            self.precision = 0
        self.belong = self.__getBlong()


class Province(Place):

    def __init__(self, name=""):
        super(Province, self).__init__()

    def __getBlong(self):
        return SuperMap.province_country_mapper.get(self.name)

    def setPlace(self, name):
        self.name, isfilled = SuperMap.fillProvince(name)
        if isfilled:  # 如果是需要补充字的，则认为这个匹配准确率比较低
            self.precision = 0
        self.belong = self.__getBlong()


class Area(Place):

    def __init__(self, name=""):
        super(Area, self).__init__()

    def __getBlong(self):
        return SuperMap.area_city_mapper.get(self.name)

    def setPlace(self, name):
        self.name = name
        self.precision = 1
        self.belong = self.__getBlong()


class Address(Place):

    def __init__(self, name=""):
        super(Address, self).__init__()

    def setPlace(self, name):
        self.name = name
        self.precision = 1


class Tsrl(Place):

    def __init__(self, name=""):
        super(Tsrl, self).__init__()

    def setPlace(self, name):
        self.name = name
        self.precision = 1
